/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dgbgui.modeldocument;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Observable;

import queryexecute.QueryDistributor;

public class ResultStore extends Observable {
    
    public static enum ObservedEventType { 
        QUERY_SUBMITTED,
        RESULT_RECEIVED,
        RESULT_REMOVED,
    }
    
    public class ObservableData {
        
        public ObservableData(ObservedEventType type, String queryStr, QueryResult result) {
            m_type = type;
            m_queryString = queryStr;
            m_result = result;
        }
        
        public ObservableData(ObservedEventType type, String queryStr) {
            m_type = type;
            m_queryString = queryStr;
        }
        
        public ObservedEventType getType() {
            return m_type;
        }
        
        public QueryResult getQueryResult() {
            return m_result;
        }
        
        public String getQueryString() {
            return m_queryString;
        }
        
        private ObservedEventType m_type;
        private QueryResult m_result;
        private String m_queryString;
    }
    
    public void addResult(String queryString, QueryResult result) {
        // This coudl come from the asyncronous query execution, or
        // from creating a query with an existing result
        
        // Remove the old query if there is one, so the
        // widgets can be removed
        if ( m_results.get(queryString) != null ) {
            setChanged();
            notifyObservers(new ObservableData(ObservedEventType.RESULT_REMOVED,queryString,m_results.get(queryString)));
        }
        
        m_results.put(queryString,result);
        
        setChanged();
        notifyObservers(new ObservableData(ObservedEventType.RESULT_RECEIVED,queryString,result));
    }
    

    public void submit(Query query) {
        String queryString = query.getDefinition().getdgbQLString();
        
        // If not already submitted, add to the result map
        if ( !m_results.containsKey(queryString)) {
            m_results.put(queryString,null);
        }
        
        
        if ( m_results.get(queryString) == null ) {
            // Submit the query
            QueryDistributor distr = QueryDistributor.getInstance();
            distr.runQuery(queryString);
            
            // Notify the observers
            setChanged();
            notifyObservers(new ObservableData(ObservedEventType.QUERY_SUBMITTED,queryString));
            
        } else {
            // Already submitted, re-use the result
            setChanged();
            notifyObservers(new ObservableData(ObservedEventType.RESULT_RECEIVED,queryString,m_results.get(queryString)));
        }

    }
    
    public boolean hasBeenSubmitted(Query query) {
        String ql = query.getDefinition().getdgbQLString();
        return m_results.containsKey(ql);
    }
    
    public boolean hasResult(Query query) {
        String ql = query.getDefinition().getdgbQLString();
        return (m_results.containsKey(ql) && (m_results.get(ql) != null));
    }
    
    public QueryResult getResult(Query query) {
        String ql = query.getDefinition().getdgbQLString();
        assert(m_results.containsKey(ql));
        return m_results.get(ql);
    }
    
    public void clear() {
        for ( String dgbQL : m_results.keySet() ) {
            
            // Could be null at this point
            if ( m_results.get(dgbQL) != null ) {
                setChanged();
                notifyObservers(new ObservableData(ObservedEventType.RESULT_REMOVED,dgbQL,m_results.get(dgbQL)));
            }
        }
        
        m_results = new HashMap<String,QueryResult>();
    }
    
    // ----- Singleton -----
    
    private ResultStore() {
        // Do nothing
    }
    
    static public ResultStore getInstance() {
        if ( m_instance == null ) {
            m_instance = new ResultStore();
        }
        return m_instance;
    }
    
    static private ResultStore m_instance;
    
    // ------------------- Serialization -------------
    
    /**
     * First serilization version
     */
    private static final long m_serialVersion = 1L;
    
    
    public void writeToStream(java.io.ObjectOutputStream stream) throws IOException {
        stream.writeLong(m_serialVersion);
        stream.writeObject(m_results);
    }
    
    
    @SuppressWarnings("unchecked")
    public void readFromStream(java.io.ObjectInputStream stream)  throws IOException, ClassNotFoundException {
        long x = stream.readLong();
        assert(x == m_serialVersion);
        m_results = (Map<String,QueryResult>)stream.readObject();

    }
    
    // ----- Fields -----
    
    private Map<String,QueryResult> m_results = new HashMap<String,QueryResult>();

}
